 /**********************************
    * Learning practices
    *
    *文件名称:01homework.c
    *文件标识:
    *摘要:子进程先拷贝前一半文件，父进程先阻塞等待子进程拷贝完前一半内容,然后父进程在拷贝，后一半内容
    *
    *当前版本:1.0
    *作者:上官筱旭
    *完成日期:2022.5.2
    *********************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char* argv[])
{
    int sfd, dfd;
    char buf[5] = { 0 };
    int status;
    off_t fileSize = 0;//文件大小
    off_t c_read_size = 0;//子进程读取文件大小
    off_t f_read_size = 0;//父进程读取文件大小

    if((sfd = open(argv[1], O_RDONLY)) < 0)
    {
        printf("open error");
        return -1;
    }
    if((dfd = open(argv[2], O_WRONLY | O_APPEND, 0666)) < 0)
    {
        printf("open error");
        return -1;
    }
    fileSize = lseek(sfd, 0, SEEK_END) - lseek(sfd, 0, SEEK_SET);
    printf("源文件大小：%ld\n",fileSize);
    c_read_size = fileSize / 2;
    f_read_size = fileSize - c_read_size;

    pid_t pid = 0;
    pid = fork();
    if(pid == -1)
    {
        perror("pid error");
        return -1;
    }
    else if(pid == 0)//子进程
    {
        printf("子进程读取文件大小：%ld\n",c_read_size);
        size_t num = 0;//记录读取个数
        size_t temp = 0;//临时读取
        while(1)
        {
            if((temp = read(sfd, buf, 1)) <= 0)
            {
                printf("child read fail or end\n");
                break;
            }
            size_t ct = 0;//子程序写入
            if((ct = write(dfd, buf, 1)) == -1)
            {
                perror("child write file fail :"); 
                break;
            }
            num += temp;
            if(num >= c_read_size)
            {
                printf("child write file end \n");
                break;
            }
        }
        printf("child write file end \n"); 
        exit(1);
    }
    else
    {
        waitpid(pid, &status, 0);//等待子进程执行完在执行
        printf("父进程读取文件大小：%ld\n",f_read_size);
        lseek(sfd, -f_read_size, SEEK_END);//移动到要复制的位置
        while(1)
        {
            size_t num = 0;//记录读取个数
            size_t temp = 0;//临时读取
            if((temp = read(sfd, buf, 1)) <= 0)
            {
                printf("father read file end\n");
                break;
            }
            size_t ct = 0;//父程序写入
            if((ct = write(dfd, buf, 1)) == -1)
            {
                perror("father write file fail :"); 
                break;
            }
        }
        printf("father write file end \n");    
        exit(1);
    }
    close(sfd);
    close(dfd);

    return 0;
}
